package fybug.nulll.pdstream.IO.File;
import com.sun.istack.internal.NotNull;
import com.sun.istack.internal.Nullable;

import org.jetbrains.annotations.NonNls;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;

import fybug.nulll.pdfunctionlibrary.Processing.Err.Stop;
import fybug.nulll.pdfunctionlibrary.Util.DataContainer;
import fybug.nulll.pdfunctionlibrary.Util.Processing.Arrarys;
import fybug.nulll.pdstream.IO.Error.Path.ParamNoDir;
import fybug.nulll.pdstream.IO.Error.Path.ParamNoFile;
import fybug.nulll.pdstream.IO.Error.Path.ParamNoPath;

import static fybug.nulll.pdfunctionlibrary.Util.Processing.Arrarys.append;
import static fybug.nulll.pdfunctionlibrary.Util.Processing.Arrarys.checkNullArray;
import static fybug.nulll.pdfunctionlibrary.Util.Processing.Arrarys.trim;
/**
 * <h2>路径操作器超类.</h2>
 * <pre>
 * <b>该类不允许直接构造,请使用子类</b>
 *
 * 提供一个存放路径的容器
 * 需绑定要操作的路径组
 * 提供 <b>路径检查方法</b>
 * 可使用本容器中的方法重绑定路径组
 * </pre>
 *
 * @author fybug
 * @version 0.0.6
 * @see DataContainer
 * @see File
 * @since JDK 1.8
 */
@SuppressWarnings( "All" )
public abstract
class AbstractFileOper extends DataContainer<File[]> implements Serializable {
    /** {@Hide} */
    @Deprecated
    private
    AbstractFileOper() {}

    /** <p>构造一个路径操作器并绑定路径组.</p> */
    protected
    AbstractFileOper(@Nullable final File... files) {super(files);}

    /** <p>构造一个路径操作器并绑定路径组.</p> */
    protected
    AbstractFileOper(@Nullable final String... s) {
        @NotNull File[] fs = new File[s.length];
        int mark = 0;
        for ( int i = 0; i < s.length; i++ ){
            @Nullable String tmp = s[i];
            if (tmp == null || tmp.isEmpty())
                continue;
            fs[mark] = new File(tmp);
            mark++;
        }
        // 去除多余的空间
        if (mark < s.length)
            fs = Arrarys.trim(fs);
        binFile(fs);
    }

    /**
     * <p>打印出所有分隔符和最大长度.</p>
     * <pre>
     * files:{
     *      [ 路径 ];
     * };
     * </pre>
     */
    @NonNls
    @NotNull
    public
    String toString() {
        @NotNull final StringBuilder stringBuffer = new StringBuilder("files:{\n");
        @NotNull final File[] files;
        try {
            files = file();
        } catch ( Stop e ) {
            return "files:{\n};\b";
        }
        int size = 0; // 记录长度
        for ( int i = 0; i < files.length; i++ )
            size += files[i].toString().length() + 5;
        size += 11;
        // 提前缓存
        stringBuffer.ensureCapacity(size);
        for ( int i = 0; i < files.length; i++ )
            // 用打印所有分隔符
            stringBuffer.append("\t[").append(files[i].toString()).append("];\n");
        stringBuffer.append("};\b");
        return stringBuffer.toString();
    }

    /** <p>获取绑定路径组的字符串型.</p> */
    @NotNull
    public
    String[] getStrings() {
        @NotNull File[] files;
        try {
            files = file();
        } catch ( Stop e ) {
            return new String[0];
        }
        return Arrarys.toStringTrim(files);
    }

    @Override
    public
    int hashCode() { return (getClass().hashCode() + super.hashCode()) << 5; }

    @Override
    public
    Object clone() {
        @NotNull final AbstractFileOper abstractFileOper = (AbstractFileOper) super.clone();
        try {
            abstractFileOper.setValue(cloneField(getValue(), this));
        } catch ( Stop e ) {
        }
        return abstractFileOper;
    }

    /*
     * File
     */

    /** <p>重绑定操作的路径.</p> */
    @NotNull
    public
    AbstractFileOper binFile(@Nullable final File... files) {
        setValue(files);
        return this;
    }

    /** <p>增加要操作的路径.</p> */
    @NotNull
    public
    AbstractFileOper appendFile(@Nullable final File... files) {
        @Nullable File[] f;
        try {
            f = file();
        } catch ( Stop ignored ) {
            f = null;
        }
        binFile(checkNullArray(append(f, trim(files))));
        return this;
    }

    /** <p>获取绑定的路径组.</p> */
    @NotNull
    public final
    File[] file() {return getValue();}

    /*
     * Oper
     */

    /** <p>移动绑定的路径组到该文件夹下，并更新绑定的路径组.</p> */
    public abstract
    AbstractFileOper mv(@NotNull final File to) throws IOException;

    /*
     * 检查
     */

    /** 检查是否是存在的文件 */
    protected static
    void checkFile(@NotNull final File from) {
        if (from.isDirectory())
            throw new ParamNoFile("Param can`t is Dir", from);
        if (!from.isFile())
            throw new ParamNoPath("Param no is Parth", from);
    }

    /** 检查是否是存在的文件夹 */
    protected static
    void checkDir(@NotNull final File from) {
        if (from.isFile())
            throw new ParamNoDir("Param can`t is File", from);
        if (!from.isDirectory())
            throw new ParamNoPath("Param no is Parth", from);
    }

    /**
     * 检查是否使用了文件夹(不应该的)
     *
     * @return 该文件是否存在
     */
    protected static
    boolean noUserDir(@NotNull final File to) {
        if (to.isDirectory())
            throw new ParamNoFile("Param can`t is Dir", to);
        return !to.isFile();
    }

    /**
     * 检查是否使用了文件(不应该的)
     *
     * @return 该文件夹是否存在
     */
    protected static
    boolean noUserFile(@NotNull final File to) {
        if (to.isFile())
            throw new ParamNoDir("Param can`t is File", to);
        return !to.isDirectory();
    }

    /*
     * 释放
     */

    /**
     * <p>彻底关闭该类.</p>
     * <pre>
     * 清空路径组引用并关闭该类
     * 关闭后不可复用
     * </pre>
     */
    @Override
    public
    void close() { super.close(); }
}
